/*
 *  Copyright 2002-2005, Mersad Team, Allameh Helli High School (NODET).
 *
 *  This program is free software, you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU Library General Public License for more details.
 *
 *  This file is created by: Mohsen Izadi
 *  and is modified by: Ahmad Boorghany
 *
 *  Released on Monday 1 August 2005, 10 Mordad 1384 by Mersad RoboCup Team.
 *  For more information please read README file.
*/

#ifndef __LOGGER_H
#define __LOGGER_H

//#include <Timer.h>
#include <sys/time.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <map>
#include <string>
#include <iomanip>

#include <unistd.h>

#include "StaticModule.h"
#include "WinLogWidget.h"
#include "types.h"

//#define LOGGER StaticModule<Logger>::getInstance()
//#define INIT_LOGGER StaticModule<Logger>::init();

#define FIELD_FILL '0'
#define FIELD_WIDTH 4
#define PRECISION 2

#define LOG StaticModule<Logger>::getInstance()["MainLog"]
#define STARS "**************************************************************"
#define WLOG StaticModule<LogWindow>::getInstance()

//#define LOG StaticModule<Logger>::getInstance()["MainLog"]
//#define LOG StaticModule<LogWindow>::getInstance()

using namespace std;

//Logger section
class LogStream
{
protected:
	std::ostream *out;
	long mCycle;
	bool logTime;
	bool first;

public:
	LogStream(std::ostream *out, bool logTime = false);
	virtual ~LogStream();

	bool isOutValid();
	void newCycle(long cycle);

	template<class T>
	LogStream &operator<<(const T &value)
	{
		//cout<<"LogStream &operator<<(const T &value)"<<endl;
		if (out)
		{
			if (first)
			{
				first = false;
				*out << "  ";
			}
			*out << value;
		}
		return *this;
	}

	LogStream &operator<<(std::ostream &(*man)(std::ostream &));
	LogStream &operator<<(std::ios_base &(*man)(std::ios_base &));
};

class LogNull: public LogStream
{
public:
	LogNull();
	virtual ~LogNull();
};

class LogFile: public LogStream
{
protected:
	std::string fileName;

public:
	LogFile(const std::string &fileName, bool logTime = true);
	virtual ~LogFile();
};

class LogStdOut: public LogStream
{
public:
	LogStdOut();
	virtual ~LogStdOut();
};

class LogStdErr: public LogStream
{
public:
	LogStdErr();
	virtual ~LogStdErr();
};

class Logger
{
protected:
	class LogStreams
	{
	protected:
		std::map<std::string, LogStream *> streams;
		LogNull logNull;

	public:
		LogStreams();
		virtual ~LogStreams();

		void add(const std::string &name, LogStream *stream);
		LogStream &operator[](const std::string &name) const;
	};

	static LogStreams *logStreams;

public:
	Logger();
	virtual ~Logger();

	void add(const std::string &name, LogStream *stream);
	LogStream &operator[](const std::string &name) const;
};

class LogWindow
{
protected:
	WinLogWidget* mWinLogWidget;

public:
	LogWindow()
	{
		//mWinLogWidget = new WinLogWidget();
	}

	template<class T>
	LogWindow& operator<<(const T &value)
	{
		ostringstream os;
		os<<value;
		string text = os.str();
		mWinLogWidget->insertText(text);

		return *this;
	}

	LogWindow& operator<<(ostream &(*man)(ostream &))
	{
		ostringstream os;
		os << man;

		string text = os.str();
		mWinLogWidget->insertText(text);

		return *this;
	}

	LogWindow& operator << (WordStatus status)
	{
		switch(status)
		{
		case WS_Finished:
			mWinLogWidget->insertText("WS_Finished");break;
		case WS_Untouched:
			mWinLogWidget->insertText("WS_Untouched");break;
		case WS_Reciting:
			mWinLogWidget->insertText("WS_Reciting");break;
		case WS_Reviewing:
			mWinLogWidget->insertText("WS_Reviewing");break;
		default:break;
		}

		return *this;
	}

	LogWindow& operator << (TestMethod testMode)
	{
		switch(testMode)
		{
		case yes_no_method:
			mWinLogWidget->insertText("yes_no_method");break;
		case multi_exp_choice_method:
			mWinLogWidget->insertText("multi_exp_choice_method");break;
		case multi_English_choice_method:
			mWinLogWidget->insertText("multi_English_choice_method");break;
		case spell_method:
			mWinLogWidget->insertText("spell_method");break;
		default:break;
		}

		return *this;
	}

	void initLogWindow(){mWinLogWidget = new WinLogWidget();}
	void show(){mWinLogWidget->show();}
	void hide(){mWinLogWidget->hide();}
	void clear(){mWinLogWidget->clear();}
};

#endif // __LOGGER_H
